﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TableTopWidgets
{
    /// <summary>
    /// Interaction logic for RNTControl.xaml
    /// </summary>
    public class RNTControl : UserControl
    {
        private bool hasControl;

        protected Point pickPoint;
        protected Matrix transformation;

        FrameworkElement _border;
        private static int _globalZIndex = 0;
        #region RNTControl Title

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public static readonly DependencyProperty TitleProperty =
          DependencyProperty.Register("Title", typeof(string), typeof(RNTControl), 
          new FrameworkPropertyMetadata("Title", FrameworkPropertyMetadataOptions.AffectsRender));
        #endregion
        #region RNTControl Text Content

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
          DependencyProperty.Register("Text", typeof(string), typeof(RNTControl), new UIPropertyMetadata("Setup"));

        #endregion
        #region RNTControl Text Color

        public static readonly DependencyProperty ColorProperty =
           DependencyProperty.Register("TextColor", typeof(Brush), typeof(RNTControl),
           new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.AffectsRender));

        public Brush TextColor
        {
            get { return (Brush)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }
        #endregion
        #region RNTControl Text Background Color

        public static readonly DependencyProperty TextBackgroundColorProperty =
   DependencyProperty.Register("TextBackgroundColor", typeof(Brush), typeof(RNTControl),
   new FrameworkPropertyMetadata(Brushes.DarkGray, FrameworkPropertyMetadataOptions.AffectsRender));

        public Brush TextBackgroundColor
        {
            get { return (Brush)GetValue(TextBackgroundColorProperty); }
            set { SetValue(TextBackgroundColorProperty, value); }
        }

        #endregion
        #region RNTControl Border Color

        public static readonly DependencyProperty BorderColorProperty =
DependencyProperty.Register("BorderColor", typeof(Brush), typeof(RNTControl),
new FrameworkPropertyMetadata(Brushes.Gray, FrameworkPropertyMetadataOptions.AffectsRender));

        public Brush BorderColor
        {
            get { return (Brush)GetValue(BorderColorProperty); }
            set { SetValue(BorderColorProperty, value); }
        }


        #endregion

        public new static readonly DependencyProperty WidthProperty;
        public new static readonly DependencyProperty HeightProperty;
        static RNTControl()
        {
            WidthProperty = FrameworkElement.WidthProperty.AddOwner(typeof(RNTControl));
            HeightProperty = FrameworkElement.HeightProperty.AddOwner(typeof(RNTControl));
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RNTControl), new FrameworkPropertyMetadata(typeof(RNTControl)));
        }
        public RNTControl()
        {
            
            Loaded += new RoutedEventHandler(OnLoad);
            transformation = new Matrix();
            hasControl = false;
        }
        /// <summary>
        /// Tells this control that it is being grabbed.
        /// </summary>
        /// <param name="x">The X coordinate in this control's coordinate system where it is grabbed.</param>
        /// <param name="y">The Y coordinate in this control's coordinate system where it is grabbed.</param>
        public void Take(double x, double y)
        {
            pickPoint = new Point(x, y);
            hasControl = true;
        }
        /// <summary>
        /// Tells this control that it is released.
        /// </summary>
        public void Release()
        {
            hasControl = false;
        }
        /// <summary>
        /// If grabbed, will move this control along a pivot where it was grabbed.
        /// </summary>
        /// <param name="x">The X coordinate of the new pivot in this control's coordinate system.</param>
        /// <param name="y">The Y coordinate of the new pivot in this control's coordinate system.</param>
        public void MoveControl(double x, double y)
        {
            if (!hasControl)
            {
                return;
            }
            Vector actual = new Vector(x, y);
            Vector center = new Vector(this.ActualWidth / 2, this.ActualHeight / 2);

            Matrix transformation = this.RenderTransform.Value;
            RotateAndTranslate.calculateRNT(new Vector(pickPoint.X, pickPoint.Y), actual, center,
                ref transformation);

            this.RenderTransform = new MatrixTransform(transformation);

            this.InvalidateVisual();
        }

        void OnLoad(object sender, RoutedEventArgs e)
        {
            this._border = (FrameworkElement)this.Template.FindName("PART_Border", this);
            
            if (this._border != null)
            {
                _border.MouseDown += new MouseButtonEventHandler(ButtonDown);
                _border.MouseMove += new MouseEventHandler(_border_MouseMove);
                _border.MouseUp += new MouseButtonEventHandler(ButtonUp);
                this.MouseDown += new MouseButtonEventHandler(moveToFront);
                //Canvas.SetZIndex(_border, 0);
            }
        }

        void moveToFront(object sender, MouseButtonEventArgs e)
        {
            MoveToFront();
        }
        public void MoveToFront()
        {
            incrementZIndex();
            Canvas.SetZIndex(this, _globalZIndex);
        }

        private void incrementZIndex()
        {
            if (_globalZIndex == Int32.MaxValue -1)
                _globalZIndex = 0;
            _globalZIndex++;
        }

        void ButtonUp(object sender, MouseButtonEventArgs e)
        {
            double x = e.GetPosition(this).X;
            double y = e.GetPosition(this).Y;
            if (!isOnBorder(x, y) || !hasControl)
            {
                return;
            }
            UIElement e1 = (UIElement)sender;
            e1.ReleaseMouseCapture();
            Release();
        }

        void _border_MouseMove(object sender, MouseEventArgs e)
        {
            double x = e.GetPosition(this).X;
            double y = e.GetPosition(this).Y;

            MoveControl(x, y);
        }

        void ButtonDown(object sender, MouseButtonEventArgs e)
        {
            double x = e.GetPosition(this).X;
            double y = e.GetPosition(this).Y;
            //Panel.SetZIndex(this, 0);
            if (!isOnBorder(x, y))
                return;
            else
                e.Handled = true;  //Disable mouse callbacks directly on the border

            UIElement e1 = (UIElement)sender;
            e1.CaptureMouse();

            Take(e.GetPosition(this).X, e.GetPosition(this).Y);
        }
        /// <summary>
        /// Test a point to see if it's on this control's border.
        /// </summary>
        /// <param name="x">The X coordinate in the control's coordinate to be tested.</param>
        /// <param name="y">The Y coordinate in the control's coordinate to be tested.</param>
        /// <returns></returns>
        public bool isOnBorder(double x, double y)
        {
            if (x >= 20 && x <= this.ActualWidth - 20
                    && y >= 20 && y <= this.ActualHeight - 20)
            {
                return false;
            }
            return true;
        }
    }
}
